/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include "NasPlugin.h"
#include <vector>
#include <unordered_set>
#include "utils/PluginUtilities.h"
#include "config_reader/ConfigIniReader.h"
#include "log/Log.h"
#include "common/EnvVarManager.h"
#include "common/Path.h"
#include "HetroCommonService.h"
#include "ApplicationServiceDataType.h"
#include "PluginConstants.h"
#include "ThreadPoolFactory.h"
#include "ScanMgr.h"
#include "nas_service/nas_resource/AppService.h"
#include "nas_service/nas_livemount/LivemountJobManager.h"
#include "ErrorCodes.h"
#include "security/cmd/CmdExecutor.h"
#include "ChannelManager.h"

using namespace std;
using namespace AppProtect;
using namespace Module;
using namespace PluginUtils;
using namespace NasChannelManager;
namespace {
static const std::string GENERALDN_LOG_NAME = "AppPlugins.log";
static const std::string GENERAL_LOG_PATH = "/DataBackup/ProtectClient/ProtectClient-E/slog/NasPlugin";
const string MODULE = "commonJobFactory";
constexpr uint64_t BACKUP_INC_TO_FULL = 1577209901;
constexpr uint64_t PARAM_ERR = 1577209902;
constexpr uint32_t TWOHUNDREDOK = 200;
static const int TASK_FAILED_NO_REPORT = -15;
static const int RET_BUSY = 101;
constexpr int DEFAULT_THREAD_POOL_COUNT = 32;
constexpr int DEFAULT_BACKUP_THREAD_POOL_COUNT = 128;
constexpr auto INTERNAL_ERROR = 200;
constexpr auto NTLM_AUTHTYPE = "ntlmssp";
constexpr auto KRB5_AUTHTYPE = "krb5";
const int BACKUP_STUCK_TIME_MIN = 120;
const int BACKUP_STUCK_TIME_MAX = 86400;
const int BACKUP_STUCK_TIME_DEFAULT = 1800;
const int CIFS_MAX_PENDING_ASYNC_REQ_CNT = 10000;
const int DEFAULT_CIFS_MAX_PENDING_ASYNC_REQ_CNT = 32;
const int CIFS_SERVER_CHECK_MAX_ERR_COUNT = 104857600;
const int DEFAULT_CIFS_SERVER_CHECK_MAX_ERR_COUNT = 100;
const int CIFS_MAX_OPENED_FILEHANDLE_COUNT = 104857600;
const int DEFAULT_CIFS_MAX_OPENED_FILEHANDLE_COUNT = 100;
const int CIFS_POLL_EXPIRED_TIME = 1000000;
const int DEFAULT_CIFS_POLL_EXPIRED_TIME = 100;
const int MAX_CONNECTION_TIMEOUT = 3600;
const int DEFAULT_CONNECTION_TIMEOUT = 60;
const string NFS_OPT = "nfs";
const string DEFAULT_CHANNEL_NUM = "10";

void InitBackupConfigurations1()
{
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_ENABLED", 0,
        MAXIMUM_DME_NAS_BACKUP_ENABLED, DEFAULT_DME_NAS_BACKUP_ENABLED);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_WRITE_ENABLE", 0,
        MAXIMUM_DME_NAS_BACKUP_WRITE_ENABLE, DEFAULT_DME_NAS_BACKUP_WRITE_ENABLE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_READ_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_BACKUP_READ_QUEUE_SIZE, DEFAULT_DME_NAS_BACKUP_READ_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_READ_BLOCK_SIZE", 1,
        MAXIMUM_DME_NAS_BACKUP_READ_BLOCK_SIZE, DEFAULT_DME_NAS_BACKUP_READ_BLOCK_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_FILEPATH_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_BACKUP_FILEPATH_QUEUE_SIZE, DEFAULT_DME_NAS_BACKUP_FILEPATH_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_NO_ROOT_SQUASH", 0,
        MAXIMUM_DME_NAS_BACKUP_NO_ROOT_SQUASH, DEFAULT_DME_NAS_BACKUP_NO_ROOT_SQUASH);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_LIBNFS_FH_CACHE_DISABLE", 0,
        MAXIMUM_DME_NAS_BACKUP_LIBNFS_FH_CACHE_DISABLE, DEFAULT_DME_NAS_BACKUP_LIBNFS_FH_CACHE_DISABLE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_THREAD_POOL_CNT", 1,
        MAXIMUM_DME_NAS_BACKUP_THREAD_POOL_CNT, DEFAULT_DME_NAS_BACKUP_THREAD_POOL_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_REMOVE_CONTROL_FILE", 0,
        MAXIMUM_DME_NAS_REMOVE_CONTROL_FILE, DEFAULT_DME_NAS_REMOVE_CONTROL_FILE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_MAX_PENDING_ASYNC_REQ_CNT",
        MINIMUM_DME_NAS_BACKUP_MAX_PENDING_ASYNC_REQ_CNT, MAXIMUM_DME_NAS_BACKUP_MAX_PENDING_ASYNC_REQ_CNT,
        DEFAULT_DME_NAS_BACKUP_MAX_PENDING_ASYNC_REQ_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_MIN_PENDING_ASYNC_REQ_CNT",
        MINIMUM_DME_NAS_BACKUP_MIN_PENDING_ASYNC_REQ_CNT, MAXIMUM_DME_NAS_BACKUP_MIN_PENDING_ASYNC_REQ_CNT,
        DEFAULT_DME_NAS_BACKUP_MIN_PENDING_ASYNC_REQ_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_MAX_PENDING_WRITE_REQ_CNT",
        MINIMUM_DME_NAS_BACKUP_MAX_PENDING_WRITE_REQ_CNT, MAXIMUM_DME_NAS_BACKUP_MAX_PENDING_WRITE_REQ_CNT,
        DEFAULT_DME_NAS_BACKUP_MAX_PENDING_WRITE_REQ_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_MIN_PENDING_WRITE_REQ_CNT",
        MINIMUM_DME_NAS_BACKUP_MIN_PENDING_WRITE_REQ_CNT, MAXIMUM_DME_NAS_BACKUP_MIN_PENDING_WRITE_REQ_CNT,
        DEFAULT_DME_NAS_BACKUP_MIN_PENDING_WRITE_REQ_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_MAX_PENDING_READ_REQ_CNT",
        MINIMUM_DME_NAS_BACKUP_MAX_PENDING_READ_REQ_CNT, MAXIMUM_DME_NAS_BACKUP_MAX_PENDING_READ_REQ_CNT,
        DEFAULT_DME_NAS_BACKUP_MAX_PENDING_READ_REQ_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_MIN_PENDING_READ_REQ_CNT",
        MINIMUM_DME_NAS_BACKUP_MIN_PENDING_READ_REQ_CNT, MAXIMUM_DME_NAS_BACKUP_MIN_PENDING_READ_REQ_CNT,
        DEFAULT_DME_NAS_BACKUP_MIN_PENDING_READ_REQ_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_REQ_CNT_PER_NFS_CONTEXT",
        MINIMUM_DME_NAS_BACKUP_REQ_CNT_PER_NFS_CONTEXT, MAXIMUM_MAX_DME_NAS_BACKUP_REQ_CNT_PER_NFS_CONTEXT,
        DEFAULT_DME_NAS_BACKUP_REQ_CNT_PER_NFS_CONTEXT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_RW_BLOCKSIZE",
        MINIMUM_DME_NAS_BACKUP_RW_BLOCKSIZE, MAXIMUM_DME_NAS_BACKUP_RW_BLOCKSIZE,
        DEFAULT_DME_NAS_BACKUP_RW_BLOCKSIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_MAX_TOTAL_BLOCK_BUFFER_CNT",
        MINIMUM_DME_NAS_BACKUP_MAX_TOTAL_BLOCK_BUFFER_CNT, MAXIMUM_DME_NAS_BACKUP_MAX_TOTAL_BLOCK_BUFFER_CNT,
        DEFAULT_DME_NAS_BACKUP_MAX_TOTAL_BLOCK_BUFFER_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_MAX_TOTAL_BLOCK_BUFFER_SIZE",
        MINIMUM_DME_NAS_BACKUP_MAX_TOTAL_BLOCK_BUFFER_SIZE, MAXIMUM_DME_NAS_BACKUP_MAX_TOTAL_BLOCK_BUFFER_SIZE,
        DEFAULT_DME_NAS_BACKUP_MAX_TOTAL_BLOCK_BUFFER_SIZE);
}

void InitBackupConfigurations2()
{
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_NAS_SERVER_CHECK_MAX_ERR_COUNT",
        MINIMUM_DME_NAS_BACKUP_NAS_SERVER_CHECK_MAX_ERR_COUNT, MAXIMUM_DME_NAS_BACKUP_NAS_SERVER_CHECK_MAX_ERR_COUNT,
        DEFAULT_DME_NAS_BACKUP_NAS_SERVER_CHECK_MAX_ERR_COUNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_NAS_SERVER_CHECK_SLEEP_TIME",
        MINIMUM_DME_NAS_BACKUP_NAS_SERVER_CHECK_SLEEP_TIME, MAXIMUM_DME_NAS_BACKUP_NAS_SERVER_CHECK_SLEEP_TIME,
        DEFAULT_DME_NAS_BACKUP_NAS_SERVER_CHECK_SLEEP_TIME);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_BACKUP_NAS_SERVER_CHECK_RETRY_CNT",
        MINIMUM_DME_NAS_BACKUP_NAS_SERVER_CHECK_RETRY_CNT, MAXIMUM_DME_NAS_BACKUP_NAS_SERVER_CHECK_SLEEP_TIME,
        DEFAULT_DME_NAS_BACKUP_NAS_SERVER_CHECK_RETRY_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_AGGR_THREAD_POOL_CNT",
        MINIMUM_DME_NAS_AGGR_THREAD_POOL_CNT, MAXIMUM_DME_NAS_AGGR_THREAD_POOL_CNT,
        DEFAULT_DME_NAS_AGGR_THREAD_POOL_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_FILE_SIZE",
        MINIMUM_DME_NAS_SCAN_CTRL_FILE_SIZE, MAXIMUM_DME_NAS_SCAN_CTRL_FILE_SIZE,
        DEFAULT_DME_NAS_SCAN_CTRL_FILE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "BACKUP_STUCK_TIME", BACKUP_STUCK_TIME_MIN,
        BACKUP_STUCK_TIME_MAX, BACKUP_STUCK_TIME_DEFAULT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "CIFS_MAX_PENDING_ASYNC_REQ_CNT", 1,
        CIFS_MAX_PENDING_ASYNC_REQ_CNT, DEFAULT_CIFS_MAX_PENDING_ASYNC_REQ_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "CIFS_SERVER_CHECK_MAX_ERR_COUNT", 1,
        CIFS_SERVER_CHECK_MAX_ERR_COUNT, DEFAULT_CIFS_SERVER_CHECK_MAX_ERR_COUNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "CIFS_MAX_OPENED_FILEHANDLE_COUNT", 1,
        CIFS_MAX_OPENED_FILEHANDLE_COUNT, DEFAULT_CIFS_MAX_OPENED_FILEHANDLE_COUNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "CIFS_POLL_EXPIRED_TIME", 0,
        CIFS_POLL_EXPIRED_TIME, DEFAULT_CIFS_POLL_EXPIRED_TIME);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "CIFS_PROTECTED_CONNECTION_TIMEOUT", 0,
        MAX_CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "CIFS_STORAGE_CONNECTION_TIMEOUT", 0,
        MAX_CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_CIFS_BACKUP_ADS", 0, 1, 1);
}

void InitScannerConfigurations()
{
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_LIBNFS_OPENDIR_REQ_CNT", 1,
        MAXIMUM_DME_NAS_SCAN_LIBNFS_OPENDIR_REQ_CNT, DEFAULT_DME_NAS_SCAN_LIBNFS_OPENDIR_REQ_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X6000_OPENDIR_REQ_CNT", 1,
        MAXIMUM_DME_NAS_SCAN_X6000_OPENDIR_REQ_CNT, DEFAULT_DME_NAS_SCAN_X6000_OPENDIR_REQ_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X6000_MAX_WRITE_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_X6000_MAX_WRITE_QUEUE_SIZE, DEFAULT_DME_NAS_SCAN_X6000_MAX_WRITE_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X6000_MAX_SCAN_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_X6000_MAX_SCAN_QUEUE_SIZE, DEFAULT_DME_NAS_SCAN_X6000_MAX_SCAN_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X6000_MIN_SCAN_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_X6000_MIN_SCAN_QUEUE_SIZE, DEFAULT_DME_NAS_SCAN_X6000_MIN_SCAN_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X6000_WRITE_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_X6000_WRITE_QUEUE_SIZE, DEFAULT_DME_NAS_SCAN_X6000_WRITE_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X6000_DIR_ENTRY_READ_COUNT", 1,
        MAXIMUM_DME_NAS_SCAN_X6000_DIR_ENTRY_READ_COUNT, DEFAULT_DME_NAS_SCAN_X6000_DIR_ENTRY_READ_COUNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X6000_DEFAULT_META_FILE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_X6000_DEFAULT_META_FILE_SIZE, DEFAULT_DME_NAS_SCAN_X6000_DEFAULT_META_FILE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X8000_OPENDIR_REQ_CNT", 1,
        MAXIMUM_DME_NAS_SCAN_X8000_OPENDIR_REQ_CNT, DEFAULT_DME_NAS_SCAN_X8000_OPENDIR_REQ_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X8000_MAX_WRITE_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_X8000_MAX_WRITE_QUEUE_SIZE, DEFAULT_DME_NAS_SCAN_X8000_MAX_WRITE_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X8000_MAX_SCAN_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_X8000_MAX_SCAN_QUEUE_SIZE, DEFAULT_DME_NAS_SCAN_X8000_MAX_SCAN_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X8000_MIN_SCAN_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_X8000_MIN_SCAN_QUEUE_SIZE, DEFAULT_DME_NAS_SCAN_X8000_MIN_SCAN_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X8000_WRITE_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_X8000_WRITE_QUEUE_SIZE, DEFAULT_DME_NAS_SCAN_X8000_WRITE_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X8000_DIR_ENTRY_READ_COUNT", 1,
        MAXIMUM_DME_NAS_SCAN_X8000_DIR_ENTRY_READ_COUNT, DEFAULT_DME_NAS_SCAN_X8000_DIR_ENTRY_READ_COUNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_X8000_DEFAULT_META_FILE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_X8000_DEFAULT_META_FILE_SIZE, DME_NAS_SCAN_X8000_DEFAULT_META_FILE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_EXTACL_DIR_ENABLED", 0,
        MAXIMUM_DME_NAS_SCAN_EXTACL_DIR_ENABLED, DEFAULT_DME_NAS_SCAN_EXTACL_DIR_ENABLED);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_EXTACL_FILE_ENABLED", 0,
        MAXIMUM_DME_NAS_SCAN_EXTACL_FILE_ENABLED, DEFAULT_DME_NAS_SCAN_EXTACL_FILE_ENABLED);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MAX_ENTRIES_FULLBKUP", 1,
        MAXIMUM_DME_NAS_SCAN_CTRL_MAX_ENTRIES_FULLBKUP, DEFAULT_DME_NAS_SCAN_CTRL_MAX_ENTRIES_FULLBKUP);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MAX_ENTRIES_INCRBKUP", 1,
        MAXIMUM_DME_NAS_SCAN_CTRL_MAX_ENTRIES_INCRBKUP, DEFAULT_DME_NAS_SCAN_CTRL_MAX_ENTRIES_INCRBKUP);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MIN_ENTRIES_FULLBKUP", 1,
        MAXIMUM_DME_NAS_SCAN_CTRL_MIN_ENTRIES_FULLBKUP, DEFAULT_DME_NAS_SCAN_CTRL_MIN_ENTRIES_FULLBKUP);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCANNER_MAX_SIZE", 1,
        MAXIMUM_DME_NAS_SCANNER_MAX_SIZE, DEFAULT_DME_NAS_SCANNER_MAX_SIZE);
}

void InitScannerConfigurations2()
{
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MIN_ENTRIES_INCRBKUP", 1,
        MAXIMUM_DME_NAS_SCAN_CTRL_MIN_ENTRIES_INCRBKUP, DEFAULT_DME_NAS_SCAN_CTRL_MIN_ENTRIES_INCRBKUP);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_FILE_TIME_SEC", 1,
        MAXIMUM_DME_NAS_SCAN_CTRL_FILE_TIME_SEC, DEFAULT_DME_NAS_SCAN_CTRL_FILE_TIME_SEC);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_THREAD_POOL_CNT", 1,
        MAXIMUM_DME_NAS_SCAN_THREAD_POOL_CNT, DEFAULT_DME_NAS_SCAN_THREAD_POOL_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_WRITE_TASK_INSTANCE_CNT", 1,
        MAXIMUM_DME_NAS_SCAN_WRITE_TASK_INSTANCE_CNT, DEFAULT_DME_NAS_SCAN_WRITE_TASK_INSTANCE_CNT);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_WRITE_TASK_START_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_WRITE_TASK_START_QUEUE_SIZE, DEFAULT_DME_NAS_SCAN_WRITE_TASK_START_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_WRITE_TASK_STOP_QUEUE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_WRITE_TASK_STOP_QUEUE_SIZE, DEFAULT_DME_NAS_SCAN_WRITE_TASK_STOP_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_DEFAULT_META_FILE_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_DEFAULT_META_FILE_SIZE, DEFAULT_DME_NAS_SCAN_DEFAULT_META_FILE_SIZE);
    ConfigReader::setStringConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MAX_DATASIZE", "10737418240");
    ConfigReader::setStringConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MIN_DATASIZE", "5368709120");
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_USE_LAST_BACKUP_TIME", 0,
        MAXIMUM_DME_NAS_SCAN_USE_LAST_BACKUP_TIME, DEFAULT_DME_NAS_SCAN_USE_LAST_BACKUP_TIME);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_LIBNFS_DIR_Q_POP_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_LIBNFS_DIR_Q_POP_SIZE, DEFAULT_DME_NAS_SCAN_LIBNFS_DIR_Q_POP_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_LIBNFS_READDIR_Q_POP_SIZE", 1,
        MAXIMUM_DME_NAS_SCAN_LIBNFS_READDIR_Q_POP_SIZE, DEFAULT_DME_NAS_SCAN_LIBNFS_READDIR_Q_POP_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_MAX_WRITE_QUEUE_SIZE",
        MINIMUM_DME_NAS_SCAN_MAX_WRITE_QUEUE_SIZE, MAXIMUM_DME_NAS_SCAN_MAX_WRITE_QUEUE_SIZE,
        DEFAULT_DME_NAS_SCAN_MAX_WRITE_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_MIN_WRITE_QUEUE_SIZE",
        MINIMUM_DME_NAS_SCAN_MIN_WRITE_QUEUE_SIZE, MAXIMUM_DME_NAS_SCAN_MIN_WRITE_QUEUE_SIZE,
        DEFAULT_DME_NAS_SCAN_MIN_WRITE_QUEUE_SIZE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CHECKPOINT_ENABLED", 0,
        MAXIMUM_DME_NAS_SCAN_CHECKPOINT_ENABLED, DEFAULT_DME_NAS_SCAN_CHECKPOINT_ENABLED);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_MAX_SCANNER_TASKS_PERNODE", 1,
        MAXIMUM_DME_NAS_MAX_SCANNER_TASKS_PERNODE, DEFAULT_DME_NAS_MAX_SCANNER_TASKS_PERNODE);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_FILE_SIZE_AGGR",
        MINIMUM_DME_NAS_SCAN_CTRL_FILE_SIZE_AGGR, MAXIMUM_DME_NAS_SCAN_CTRL_FILE_SIZE_AGGR,
        DEFAULT_DME_NAS_SCAN_CTRL_FILE_SIZE_AGGR);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MAX_ENTRIES_FULLBKUP_AGGR", 1,
        MAXIMUM_DME_NAS_SCAN_CTRL_MAX_ENTRIES_FULLBKUP_AGGR, DEFAULT_DME_NAS_SCAN_CTRL_MAX_ENTRIES_FULLBKUP_AGGR);
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MAX_ENTRIES_INCRBKUP_AGGR", 1,
        MAXIMUM_DME_NAS_SCAN_CTRL_MAX_ENTRIES_INCRBKUP_AGGR, DEFAULT_DME_NAS_SCAN_CTRL_MAX_ENTRIES_INCRBKUP_AGGR);

    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MIN_ENTRIES_FULLBKUP_AGGR", 1,
        MAXIMUM_DME_NAS_SCAN_CTRL_MIN_ENTRIES_FULLBKUP_AGGR, DEFAULT_DME_NAS_SCAN_CTRL_MIN_ENTRIES_FULLBKUP_AGGR);
    
    ConfigReader::setIntConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MIN_ENTRIES_INCRBKUP_AGGR", 1,
        MAXIMUM_DME_NAS_SCAN_CTRL_MIN_ENTRIES_INCRBKUP_AGGR, DEFAULT_DME_NAS_SCAN_CTRL_MIN_ENTRIES_INCRBKUP_AGGR);
    ConfigReader::setStringConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MAX_DATASIZE_AGGR", "10737418240");
    ConfigReader::setStringConfigInfo(DME_NAS_CONFIG_SECTION, "DME_NAS_SCAN_CTRL_MIN_DATASIZE_AGGR", "5368709120");
}

void RegistCmdWhiteList()
{
    std::vector<std::string> cmd = {
        "mkdir",
        "cd",
        "tar",
        "curl",
        "umount",
        "rm",
        "mount",
        "pigz",
        "echo"
    };
    std::string checkIpPath = Module::CPath::GetInstance().GetRootPath() + "/bin/checkIp.sh";
    std::string krb5ScriptPath = Module::CPath::GetInstance().GetRootPath() + "/bin/krb5KinitTGT.sh";
    std::string checkMountPath = Module::CPath::GetInstance().GetRootPath() + "/bin/checkMount.sh";
    std::string binPath = Module::CPath::GetInstance().GetRootPath() + "/bin";
    
    std::vector<std::string> script = {
        checkIpPath,
        krb5ScriptPath,
        checkMountPath,
        binPath
    };
    std::unordered_set<std::string> cmdList;
    std::unordered_set<std::string> scriptList;
    for (const std::string& str : cmd) {
        INFOLOG("Register cmd : %s", str.c_str());
        cmdList.insert(str);
    }
    for (const std::string& str : script) {
        INFOLOG("Register script : %s", str.c_str());
        scriptList.insert(str);
    }
    Module::RegisterWhitelist(cmdList, scriptList);
}

bool GetAuthTypeAndInitTGT(const Application& application, std::string &cifsAuthType)
{
    if (application.auth.authType == AuthType::type::KERBEROS) {
        cifsAuthType = KRB5_AUTHTYPE;
        NasAuthExtentInfo authExtendInfo {};
        if (!JsonHelper::JsonStringToStruct(application.auth.extendInfo, authExtendInfo)) {
            ERRLOG("NasAuthExtentInfo is invaild.");
            return false;
        }
        if (KinitTGTInner(application.auth.authkey, authExtendInfo.password,
            authExtendInfo.keytab, authExtendInfo.krb5Conf, application.id) != MP_SUCCESS) {
            ERRLOG("Faild to validate kerberos authentication");
            return false;
        }
    } else if (application.auth.authType == AuthType::type::APP_PASSWORD) {
        cifsAuthType = NTLM_AUTHTYPE;
    } else {
        ERRLOG("Invalid authType: %d", application.auth.authType);
        return false;
    }
    return true;
}


SmbContextArgs GetSmbConnectParams(const NasShareExtendInfo& extendInfo, const Application& application,
    const std::string &cifsAuthType)
{
    bool smbEncryption = (extendInfo.encryption == SMB_ENCRYPTION);
    string agentHomePath = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    string krb5CcnameFile = agentHomePath + KRB5CCNAMEPREFIX + application.id;
    string krb5ConfigFile = agentHomePath + KRB5CONFIGPREFIX + application.id + KRB5CONFIGPOSTFIX;
    INFOLOG("krb5CcnameFile = %s, krb5ConfigFile = %s", krb5CcnameFile.c_str(), krb5ConfigFile.c_str());

    SmbContextArgs smbContextArgs {
        extendInfo.domainName,
        "",
        application.name,
        application.auth.authkey,
        application.auth.authPwd,
        krb5CcnameFile,
        krb5ConfigFile,
        smbEncryption,
        false,
        60,
        SmbAuthType::NTLMSSP,
        SmbVersion::VERSION0300
    };
    
    if (cifsAuthType == KRB5_AUTHTYPE) {
        smbContextArgs.authType = SmbAuthType::KRB5;
    } else if (cifsAuthType == NTLM_AUTHTYPE) {
        smbContextArgs.authType = SmbAuthType::NTLMSSP;
    } else {
        ERRLOG("invalid authType for cifs share: %s", cifsAuthType.c_str());
    }
    return smbContextArgs;
}

bool CheckSmbConnection(SmbContextArgs& smbContextArgs, const std::vector<std::string> &nasServerIpList)
{
    vector<SmbVersion> cifsVersionList {
        SmbVersion::VERSION0302,
        SmbVersion::VERSION0300,
        SmbVersion::VERSION0210,
        SmbVersion::VERSION0202
    };

    for (const auto &version : cifsVersionList) {
        smbContextArgs.version = version;
        for (const auto &ip : nasServerIpList) {
            DBGLOG("check smb connection, try ip = %s, version = %d", ip.c_str(), version);
            smbContextArgs.server = ip;
            SmbContextWrapper smbContextWrapper(smbContextArgs);
            if (!smbContextWrapper.Init()) {
                continue;
            }
            if (smbContextWrapper.SmbConnect()) {
                return true;
            }
        }
    }
    return false;
}

int64_t CheckNFSMount(NasMountParams param, std::string &outSelectedSvcIp)
{
    if (param.version.empty()) {
        param.version = NFS_VERSION_3;
    } else if (param.version != NFS_VERSION_3) {
        ERRLOG("Not support NFS version: %s", param.version.c_str());
        return HomoErrorCode::ERROR_NAS_PROTOCOL_VERSION_DONOT_SUPPORT;
    }

    if (CheckNfsAccessibility(param) == MP_SUCCESS) {
        return MP_SUCCESS;
    }

    return HomoErrorCode::INTERNAL_ERROR_CODE;
}

}

NASPLUGIN_API int AppInit(std::string &logPath)
{
    string logFilePath;
    if (logPath.empty()) {
        logFilePath = Module::EnvVarManager::GetInstance()->GetAgentHomePath() + GENERAL_LOG_PATH;
    } else {
        logFilePath = logPath;
    }
    int iLogLevel = ConfigReader::getInt(string(MS_CFG_GENERAL_SECTION), string(MS_CFG_LOG_LEVEL));
    int iLogCount = ConfigReader::getInt(string(MS_CFG_GENERAL_SECTION), string(MS_CFG_LOG_COUNT));
    int iLogMaxSize = ConfigReader::getInt(string(MS_CFG_GENERAL_SECTION), string(MS_CFG_LOG_MAX_SIZE));

    CLogger::GetInstance().Init(GENERALDN_LOG_NAME.c_str(), logFilePath);
    CLogger::GetInstance().SetLogConf(iLogLevel, iLogCount, iLogMaxSize);
    string rootPath = CPath::GetInstance().GetRootPath();
    Module::CPath::GetInstance().SetRootPath(rootPath);
    Module::ThreadPoolFactory::InitThreadPool(DEFAULT_THREAD_POOL_COUNT, DEFAULT_BACKUP_THREAD_POOL_COUNT);

    InitBackupConfigurations1();
    InitBackupConfigurations2();
    InitScannerConfigurations();
    InitScannerConfigurations2();
    RegistCmdWhiteList();
    Module::ConfigReader::refresh(Module::ConfigReader::getConfigFiles());
    HCP_Log(INFO, "AppInit") << "App init success." << HCPENDLOG;
    return 0;
}

NASPLUGIN_API void DiscoverHostCluster(ApplicationEnvironment& returnEnv, const ApplicationEnvironment& appEnv)
{
    (void)returnEnv;
    (void)appEnv;
    return;
}

NASPLUGIN_API void DiscoverAppCluster(ApplicationEnvironment& returnEnv, const ApplicationEnvironment& appEnv,
    const Application& application)
{
    (void)returnEnv;
    (void)appEnv;
    (void)application;
    return;
}

NASPLUGIN_API JobFactoryBase* CreateFactory()
{
    HCP_Log(INFO, MODULE) << "Enter nas plugin create factory." << HCPENDLOG;
    return CommonJobFactory::GetInstance();
}

NASPLUGIN_API void CheckApplication(ActionResult& returnValue,
    const ApplicationEnvironment& appEnv, const Application& application)
{
    string nasShareName = application.name[0] == '/' ? application.name : "/" + application.name;
    string localMountPath = "/mnt/" + application.id;
    string tempFileName = localMountPath + "/" + "checkMount_" + application.id;
    string version {};
    string tempIp {};
    string authType;
    INFOLOG("Application subType = %s, nasShareName=  %s, localMountPath = %s, tempFileName = %s",
        application.subType.c_str(), nasShareName.c_str(), localMountPath.c_str(), tempFileName.c_str());

    returnValue.code = HomoErrorCode::INTERNAL_ERROR_CODE;
    NasShareExtendInfo extendInfo {};
    if (!JsonHelper::JsonStringToStruct(application.extendInfo, extendInfo)) {
        ERRLOG("NasShareExtendInfo is invaild.");
        return;
    }
    vector<string> ipList;
    // extendInfo.ip是界面上的IP或者域名
    // 如果是域名解析获取IP列表，如果是IP就返回IP
    ResolveDomain(extendInfo.ip, ipList);
    // 针对解析出的IP列表，按顺序对IP做检查，使用可以加上路由的IP进行连通性检测
    // ipList是最后连通性检测的IP列表

    if (!OperateIpsRuleForRemoteIp(ipList, "ADD", tempIp)) {
        ERRLOG("add ip rule failed");
        returnValue.code = Module::FAILED;
        return;
    }
    if (extendInfo.shareMode == SMB_PROTOCOL) {
        string cifsAuthType {};
        if (!GetAuthTypeAndInitTGT(application, cifsAuthType)) {
            return;
        }
        SmbContextArgs smbContextArgs = GetSmbConnectParams(extendInfo, application, cifsAuthType);
        if (!CheckSmbConnection(smbContextArgs, {tempIp})) {
            ERRLOG("Failed to connect cifs share %s", nasShareName.c_str());
            return;
        }
    } else if (extendInfo.shareMode == NFS_PROTOCOL) {
        NasMountParams mountParams(NFS_OPT, version, nasShareName, tempFileName, NFS_MOUNT_OPTION, "", "", {tempIp});
        int64_t ret = CheckNFSMount(mountParams, tempIp);
        if (ret != MP_SUCCESS) {
            ERRLOG("Failed to connect nfs share path %s", nasShareName.c_str());
            returnValue.code = ret;
            return;
        }
    } else {
        ERRLOG("invalid share mode %s", extendInfo.shareMode.c_str());
        return;
    }

    returnValue.code = MP_SUCCESS;
    if (!OperateIpsRuleForRemoteIp(ipList, "DELETE", tempIp)) {
        WARNLOG("delete ip rule failed, %s", tempIp.c_str());
    }
    return;
}

NASPLUGIN_API void ListApplicationResource(vector<ApplicationResource>& returnValue,
    const ApplicationEnvironment& appEnv, const Application& application,
    const ApplicationResource& parentResource)
{
    AppServiceExport::ListApplicationResource(returnValue, appEnv, application, parentResource);
}

NASPLUGIN_API void ListApplicationResourceV2(ResourceResultByPage& returnValue, const ListResourceRequest& request)
{
    (void)returnValue;
    (void)request;
    return;
}

NASPLUGIN_API void AbortJob(ActionResult& returnValue, const string& jobId,
    const string& subJobId, const string& appType)
{
    (void)returnValue;
    (void)jobId;
    (void)subJobId;
    (void)appType;
    return;
}

NASPLUGIN_API void PauseJob(ActionResult& returnValue, const string& jobId,
    const string& subJobId, const string& appType)
{
    (void)returnValue;
    (void)jobId;
    (void)subJobId;
    (void)appType;
    return;
}

bool ReadLastCopyDetails(std::string metaFileFullPath, HetroLastCopyDetails &backupCopy)
{
    std::ifstream readFd {};
    int retryCnt = 0;

    do {
        readFd.open(metaFileFullPath.c_str(), std::ios::in);
        if (readFd.is_open()) {
            break;
        }
        readFd.close();
        sleep(NUMBER1);
    } while (++retryCnt < NUMBER3);

    if (!readFd.is_open()) {
        char errmsg[NUMBER256];
        strerror_r(errno, errmsg, NUMBER256);
        HCP_Log(ERR, MODULE) << "Read " << WIPE_SENSITIVE(metaFileFullPath) << " failed, ERR: "
            << errmsg << HCPENDLOG;

        return false;
    }

    stringstream jsonFileContent {};
    jsonFileContent << readFd.rdbuf();
    readFd.close();
    HCP_Log(DEBUG, MODULE) << "ReadLastCopyDetails read: " << WIPE_SENSITIVE(jsonFileContent.str()) <<  HCPENDLOG;

    if (!JsonHelper::JsonStringToStruct(jsonFileContent.str(), backupCopy)) {
        HCP_Log(ERR, MODULE) << "Read " << WIPE_SENSITIVE(metaFileFullPath)
        << " failed, ERR: Json covert failed" << HCPENDLOG;
        return false;
    }

    return true;
}

static bool CheckLastCopyId(const AppProtect::BackupJob& job)
{
    if (job.jobParam.backupType == AppProtect::BackupJobType::FULL_BACKUP) {
        DBGLOG("Full backup, do not need get last copy, jobId: %s", job.jobId.c_str());
        return true;
    }
    INFOLOG("CheckLastCopyId, jobId: %s", job.jobId.c_str());
    Copy lastCopy;
    std::set<AppProtect::CopyDataType> dataTypes {
        AppProtect::CopyDataType::INCREMENT_COPY,
        AppProtect::CopyDataType::FULL_COPY,
        AppProtect::CopyDataType::PERMANENT_INCREMENTAL_COPY
    };
    Application appInfo = job.protectObject;
    int retryCnt = 0;
    do {
        try {
            // copyId需要穿空值，获取最新的副本
            JobService::QueryPreviousCopy(lastCopy, appInfo, dataTypes, "", job.jobId);
        } catch (AppProtectFrameworkException &e) {
            WARNLOG("QueryPreviousCopy failed, code: %d, retry: %d, jobId: %s", e.code, retryCnt, job.jobId.c_str());
            if (e.code == E_QUERIED_RESOURCE_NOT_EXIST) {
                ERRLOG("Exit QueryPreviousCopy, jobId: %s, last copy not exist!", job.jobId.c_str());
                return false;
            }
            sleep(NUMBER3);
            continue;
        } catch (...) {
            ERRLOG("unknown exception happened, QueryPreviousCopy failed!");
            return false;
        }
        DBGLOG("Exit CheckLastCopyId, queryLastCopy success: %s for job: %s", lastCopy.id.c_str(), job.jobId.c_str());
        return true;
    } while (++retryCnt <= NUMBER3);
    ERRLOG("Exit CheckLastCopyId, failed to queryLastCopy for job: %s, after max retry & failed", job.jobId.c_str());
    return false;
}

static bool ShouldSwitchBackupFromIncToFull(
    const std::string& metaFileFullPath,
    const std::string& previousCacheDir,
    const HetroDataLayOutExtend& dataLayout,
    const HetroNasExtent& nasShareExt,
    const AppProtect::BackupJob& job)
{
    INFOLOG("enter ShouldSwitchBackupFromIncToFull, metaFileFullPath: %s, previousCacheDir: %s",
        metaFileFullPath.c_str(), previousCacheDir.c_str());
    // check last copy id, switch to inc if failed
    if (!CheckLastCopyId(job)) {
        WARNLOG("failed to call QueryPreviousCopy to obtain last copy id, switch backup from inc to full");
        return true;
    }

    // read last backup copy meta json to compare filter and format
    HetroLastCopyDetails oldCopyDetail {};
    if (!ReadLastCopyDetails(metaFileFullPath, oldCopyDetail)) {
        WARNLOG("last backup detail backup-copy-meta.json not found, switch backup from inc to full");
        return true;
    }

    HCP_Log(INFO, MODULE) << "Check for increment to full"
            << ", reqOld.m_metadataBackupType: " << oldCopyDetail.m_metadataBackupType
            << ", reqNew.m_metadataBackupType: " << dataLayout.metaDataBackupType
            << ", reqOld.m_backupFormat: " << oldCopyDetail.m_backupFormat
            << ", reqNew.m_backupFormat: " << dataLayout.backupFormat
            << ", reqOld.m_backupFilter: " << oldCopyDetail.m_backupFilter
            << ", reqNew.m_backupFilter: " << nasShareExt.m_filters
            << ", reqOld.m_lastBackupTime: " << oldCopyDetail.m_lastBackupTime << HCPENDLOG;
    if ((oldCopyDetail.m_metadataBackupType != dataLayout.metaDataBackupType) ||
        (oldCopyDetail.m_backupFormat != dataLayout.backupFormat) ||
        (oldCopyDetail.m_backupFilter != nasShareExt.m_filters) ||
        (oldCopyDetail.m_lastBackupTime == 0)) {
        WARNLOG("backup copy meta json content missmatch, switch backup from inc to full");
        return true;
    }

    if (!IsDirExist(previousCacheDir)) {
        WARNLOG("previous cache repo dir %s not exist, switch backup from inc to full", previousCacheDir.c_str());
        return true;
    }

    return false;
}

bool InnerCheckBackupJobType(ActionResult& returnValue, std::string metaFsPath,
    std::string cacheFs, const AppProtect::BackupJob& job)
{
    std::string backupCopyMetaFile = metaFsPath + "/backup-copy-meta.json";
    std::string previousCacheDir = GetPathName(cacheFs) + "/backup-job/scan/meta/previous";

    HetroNasExtent nasShareExt;
    if (!JsonHelper::JsonStringToStruct(job.protectObject.extendInfo, nasShareExt)) {
        ERRLOG("JsonStringToStruct failed.");
        return false;
    }

    HetroDataLayOutExtend dataLayout;
    if (!JsonHelper::JsonStringToStruct(job.extendInfo, dataLayout)) {
        ERRLOG("JsonStringToStruct failed.");
        return false;
    }

    if (ShouldSwitchBackupFromIncToFull(backupCopyMetaFile, previousCacheDir, dataLayout, nasShareExt, job)) {
        returnValue.__set_code(TWOHUNDREDOK);
        returnValue.__set_bodyErr(BACKUP_INC_TO_FULL);
        returnValue.__set_message("coverting from incremental backup to full backup");
        return false;
    }

    return true;
}

NASPLUGIN_API void CheckBackupJobType(ActionResult& returnValue, const AppProtect::BackupJob& job)
{
    HCP_Log(INFO, MODULE) << "Enter file plugin CheckBackupJobType." << HCPENDLOG;
    returnValue.__set_code(0);
    if (job.jobParam.backupType == AppProtect::BackupJobType::FULL_BACKUP) {
        return;
    }

    HetroNasExtent nasShareExt;
    HetroDataLayOutExtend dataLayout;
    if (!JsonHelper::JsonStringToStruct(job.protectObject.extendInfo, nasShareExt)) {
        HCP_Log(ERR, MODULE) << "JsonStringToStruct failed." << HCPENDLOG;
        return;
    }

    if (nasShareExt.m_protocol != NAS_PROTOCOL_TYPE_E_CIFS && nasShareExt.m_protocol != NAS_PROTOCOL_TYPE_E_NFS) {
        return;
    }

    if (!JsonHelper::JsonStringToStruct(job.extendInfo, dataLayout)) {
        HCP_Log(ERR, MODULE) << "JsonStringToStruct failed." << HCPENDLOG;
        return;
    }

    std::string metaFsPath;
    for (unsigned int i = 0; i < job.repositories.size(); i++) {
        if (job.repositories[i].repositoryType == RepositoryDataType::META_REPOSITORY) {
            if (!job.repositories[i].path.empty()) {
                metaFsPath = job.repositories[i].path[0];
                DBGLOG("CheckBackupJobType metaFsPath = %s ", metaFsPath.c_str());
            }
            break;
        }
    }

    if (ValidateFsPath(returnValue, metaFsPath)) {
        return;
    }

    std::string cacheFs;
    for (unsigned int i = 0; i < job.repositories.size(); i++) {
        if (job.repositories[i].repositoryType == RepositoryDataType::CACHE_REPOSITORY) {
            if (!job.repositories[i].path.empty()) {
                cacheFs = job.repositories[i].path[0];
            }
            break;
        }
    }

    if (ValidateFsPath(returnValue, cacheFs)) {
        return;
    }

    if (!InnerCheckBackupJobType(returnValue, metaFsPath, cacheFs, job)) {
        HCP_Log(WARN, MODULE) << "Check for inc to full failed, main task id is: " << job.jobId << HCPENDLOG;
        return;
    }
    return;
}

bool ValidateFsPath(ActionResult& returnValue, std::string fsName)
{
    if (fsName.empty()) {
        ERRLOG("Job param passed is invalid");
        returnValue.__set_code(TWOHUNDREDOK);
        returnValue.__set_bodyErr(PARAM_ERR);
        returnValue.__set_message("Job param passed is invalid");
        return true;
    }

    return false;
}

template<typename T>
string GetChannelNum(const T& job)
{
    HetroProtectAdvParms advParams{};
    try {
        if (!Module::JsonHelper::JsonStringToStruct(job.extendInfo, advParams)) {
            WARNLOG("JsonStringToStruct failed, m_advParms");
            advParams.m_channels = DEFAULT_CHANNEL_NUM;
        }
    } catch (const std::exception& e) {
        WARNLOG("get channelnums failed err: %s", WIPE_SENSITIVE(e.what()));
        return DEFAULT_CHANNEL_NUM;
    } catch (...) {
        WARNLOG("get channelnums failed");
        return DEFAULT_CHANNEL_NUM;
    }

    if (advParams.m_channels.empty()) {
        advParams.m_channels = DEFAULT_CHANNEL_NUM;
        WARNLOG("channel num is empty, set to default");
    }
    return advParams.m_channels;
}

NASPLUGIN_API void AllowBackupInLocalNode(ActionResult& returnValue, const AppProtect::BackupJob& job,
    const AppProtect::BackupLimit::type limit)
{
    HCP_Log(INFO, MODULE) << "Enter file plugin AllowBackupInLocalNode." << HCPENDLOG;
    returnValue.__set_code(0);
    return ;
}

NASPLUGIN_API void AllowBackupSubJobInLocalNode(
    ActionResult& returnValue, const AppProtect::BackupJob& job, const AppProtect::SubJob& subJob)
{
    HCP_Log(INFO, MODULE) << "Enter Nas plugin AllowBackupSubJobInLocalNode." << HCPENDLOG;
    string numOfChannels = GetChannelNum(job);
    if (ChannelManager::GetInstance().AcceptSubJob(job.jobId, subJob.subJobId, numOfChannels)) {
        int numInMap = ChannelManager::GetInstance().GetSubJobCount(job.jobId);
        INFOLOG("Channel limit num: %s,current size: %d,jobId: %s,subJobId: %s",
                numOfChannels.c_str(),
                numInMap,
                job.jobId.c_str(),
                subJob.subJobId.c_str());
        returnValue.__set_code(0);
    } else {
        int numInMap = ChannelManager::GetInstance().GetSubJobCount(job.jobId);
        WARNLOG("channel num is reached max number: %s,current size: %d,jobId: %s,subJobId: %s",
                numOfChannels.c_str(),
                numInMap,
                job.jobId.c_str(),
                subJob.subJobId.c_str());
        returnValue.__set_bodyErr(TASK_FAILED_NO_REPORT); // set body err to let agent not to report auth failed.
        returnValue.__set_code(RET_BUSY);
    }
    return;
}

NASPLUGIN_API void AllowRestoreInLocalNode(ActionResult& returnValue, const AppProtect::RestoreJob& job)
{
    HCP_Log(INFO, MODULE) << "Enter file plugin AllowRestoreInLocalNode." << HCPENDLOG;
    (void)job;
    returnValue.__set_code(0);
    return ;
}

NASPLUGIN_API void AllowRestoreSubJobInLocalNode(
    ActionResult& returnValue, const AppProtect::RestoreJob& job, const AppProtect::SubJob& subJob)
{
    HCP_Log(INFO, MODULE) << "Enter Nas plugin AllowRestoreSubJobInLocalNode." << HCPENDLOG;
    string numOfChannels = GetChannelNum(job);
    if (ChannelManager::GetInstance().AcceptSubJob(job.jobId, subJob.subJobId, numOfChannels)) {
        INFOLOG("Channel limit num: %s,current size: %d,jobId: %s,subJobId: %s",
                numOfChannels.c_str(),
                ChannelManager::GetInstance().GetSubJobCount(job.jobId),
                job.jobId.c_str(),
                subJob.subJobId.c_str());
        returnValue.__set_code(0);
    } else {
        WARNLOG("channel num is reached max number: %s,current size: %d,jobId: %s,subJobId: %s",
                numOfChannels.c_str(),
                ChannelManager::GetInstance().GetSubJobCount(job.jobId),
                job.jobId.c_str(),
                subJob.subJobId.c_str());
        returnValue.__set_bodyErr(TASK_FAILED_NO_REPORT); // set body err to let agent not to report auth failed.
        returnValue.__set_code(RET_BUSY);
    }
    return;
}

NASPLUGIN_API void QueryJobPermission(AppProtect::JobPermission& returnJobPermission, const Application& application)
{
    (void)returnJobPermission;
    (void)application;
    return ;
}

NASPLUGIN_API void DeliverTaskStatus(AppProtect::ActionResult& actionResult, const std::string& status,
    const std::string& jobId, const std::string& script)
{
    INFOLOG("DeliverTaskStatus Get Called : %s, %s, %s", jobId.c_str(), status.c_str(), script.c_str());
    LivemountJobStatus jobStatus = status == "success" ? LivemountJobStatus::SUCCESS : LivemountJobStatus::FAILED;
    // livemount 任务在后面有后缀
    int ret = LivemountJobManager::GetInstance().UpdateJobStatus(jobId + "_live_mount", jobStatus);
    if (ret != Module::SUCCESS) {
        ERRLOG("Update job status failed! %s, %d", jobId.c_str(), static_cast<int>(jobStatus));
        actionResult.__set_code(INNER_ERROR);
    }
    INFOLOG("Update job status: %s, %d", jobId.c_str(), static_cast<int>(jobStatus));
    return;
}